现实中的问题:我手中有一个列表[(’请求网页’,’网页1’),(’解析网页’,’网页1’, (‘保存网页’, ‘网页1’),’请求网页’,’网页2’),(’解析网页’,’网页2’, (‘保存网页’, ‘网页2’),… ],想将列表中的事情从头到尾都干一遍。
首先,定义一个类
1
2
3
4
5
6
7class Spider:
def request(self, page):
print('请求网页:', page)
def parse(self, page):
print('解析网页:', page)
def save(self, page):
print('保存网页:', page)然后我们想的是,如何复用Spider里的方法
许多人的做法是直接使用eval
做法如下1
2
3
4
5todo_lst = [('request', 'www.exobrain.online'), ('parse', 'www.exobrain.online'), ('save', 'www.exobrain.online'),('request', 'www.exobrain.online/categories/'), ('parse', 'www.exobrain.online/categories/'), ('save', 'www.exobrain.online/categories/'), ('方法测试1','www.exobrain.online/categories/')]
spider = Spider()
for item in todo_lst:
string = 'spider.' + item[0]+'("'+item[1]+'")'
eval(string)
出来了结果
1 | 请求网页: www.exobrain.online |
我们看到了报错,自然可以用try except处理。
but,eval is evil, it’s not suggested. If you use eval, python is no longer elegant.
So, we introduce the inbuit methods “getattr, hasattr, setattr“
(参考自https://stackoverflow.com/questions/3061/calling-a-function-of-a-module-by-using-its-name-a-string
不得不感慨国内外的差距,人家11years前解决的问题,我们到现在还有好多程序员处于问题之中,还在大量使用eval()。)
使用getattr代替eval, 将for部分注释掉重写如下
1 | todo_lst = [('request', 'www.exobrain.online'), ('parse', 'www.exobrain.online'), ('save', 'www.exobrain.online'),('request', 'www.exobrain.online/categories/'), ('parse', 'www.exobrain.online/categories/'), ('save', 'www.exobrain.online/categories/'), ('方法测试1','www.exobrain.online/categories/')] |
我们看到了漂亮的结果,有没有发现上面的hasattr+getattr的代码比eval的代码更加优雅。
I choose getattr instead of eval just because of elegance. 😃
1 | 请求网页: www.exobrain.online |
动态将函数添加到类或者对象里面
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22def method_added(page):
print('调用method_added函数',page)
# 将method_added 注册到spider对象里
setattr(spider, 'method_added', method_added)
# 测试method_added是否添加到spider对象里
print(hasattr(spider, 'method_added'))
# >True 返回值为True, 添加成功
getattr(spider, 'method_added')('www.exobrain.online')
# > 调用method_added函数 www.exobrain.online
def method_added2(self, page):
print('调用method_added2函数',page)
# 将method_added2 注册到Spider类里
setattr(Spider, 'method_added2', method_added2)
# 测试method_added是否添加到spider对象里
print(hasattr(spider, 'method_added2'))
# >True 返回值为True, 添加成功
getattr(spider, 'method_added2')('www.exobrain.online')
# > 调用method_added函数 www.exobrain.online对于函数调用怎么办?
我们可以使用locals 和 globals。locals() 和 globals() 是python的两个内置函数,通过它们可以一字典的方式访问局部和全局变量。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17def foo():
print "foo"
def bar():
print "bar"
func_list = ["foo","bar"]
for func in func_list:
locals()[func]()
# >foo
# >bar
for func in func_list:
globals()[func]()
# >foo
# >bar
参考:
https://stackoverflow.com/questions/3061/calling-a-function-of-a-module-by-using-its-name-a-string